package lazy2.tool;

import java.io.*;
import java.net.*;
import lazy2.util.StringUtil;

public class LazyHttpClient {
	public static final String METHOD_GET = "GET";
	public static final String METHOD_POST = "POST";
	public static final String URLENCODED = "application/x-www-form-urlencoded";
	public static final String MULTIPART = "multipart/form-data";
	
	private final String PREFIX = "--";
	private final String NEWLINE = "\r\n";
	private final String BOUNDARY = "bet.webcam.HttpSubmitter";
	
	private boolean isDoOuput;
	private String method;
	private String url;
	private boolean isMultipart;
	private String charSet = "UTF-8";
	private HttpURLConnection con;
	private DataOutputStream out;
	private boolean alreadyOuputParam = false;
	
	
	/**
	 * GET and doOutput=false
	 * @param url
	 */
	public LazyHttpClient(String url) {
		this(false, METHOD_GET, url, null, null);
	}
	/**
	 * POST and doOutput=true
	 * @param url
	 * @param contentType
	 */
	public LazyHttpClient(String url, String contentType) {
		this(true, METHOD_POST, url, contentType, null);
	}
	private LazyHttpClient(boolean isDoOutput, String method, String url, String contentType, String charSet) {
		if(!StringUtil.hasText(url)) throw new IllegalArgumentException("必須要有url。");
		if(isDoOutput && !StringUtil.hasText(contentType)) throw new IllegalArgumentException("必須要有contentType。");
		
		this.isDoOuput = isDoOutput;
		this.method = method;
		this.url = url;
		if(isDoOutput) {
			if(URLENCODED.equals(contentType)) {
				isMultipart = false;
			} else if(MULTIPART.equals(contentType)) {
				isMultipart = true;
			} else {
				throw new IllegalArgumentException("未知的Content-Type。");
			}
		}
		if(charSet!=null) this.charSet = charSet;
	}
	public void connect() throws IOException {
		con = (HttpURLConnection)new URL(url).openConnection();
		con.setDoInput(true);
		con.setDoOutput(isDoOuput);
		con.setRequestMethod(method);
		con.setRequestProperty("Accept", "*/*");
		con.setRequestProperty("Connection", "Keep-Alive");
		if(isDoOuput) {
			if(isMultipart) {
				con.setRequestProperty("Content-Type", MULTIPART+"; boundary="+BOUNDARY);
			} else {
				con.setRequestProperty("Content-Type", URLENCODED);			
			}
			out = new DataOutputStream(con.getOutputStream());
		}
	}
	public void addParameter(String name, String value) throws IOException {
		addParameter(name, null, value.getBytes());
	}
	public void addFile(String name, String fileName, byte[] file) throws IOException {
		if(isDoOuput && !isMultipart) throw new IllegalAccessError("Content-Type並非"+MULTIPART+"。");
		addParameter(name, fileName, file);
	}
	private void addParameter(String name, String fileName, byte[] value) throws IOException {
		if(isDoOuput) {
			if(out==null) throw new IllegalArgumentException("在addParameter(String name, String value)之前，請先呼叫connect()方法。");
			if(name==null || name.length()==0) throw new IllegalArgumentException("參數name必須有值。");
			if(value==null || value.length==0) value = "".getBytes();
			
			if(isMultipart) {
				out.writeBytes(PREFIX);
				out.writeBytes(BOUNDARY);
				out.writeBytes(NEWLINE);
				// write content header
				if(fileName!=null && fileName.length()>0) {
					out.writeBytes("Content-Disposition: form-data; name=\""+name+"\"; filename=\""+fileName+"\"");
				} else {
					out.writeBytes("Content-Disposition: form-data; name=\""+name+"\"");
				}
				out.writeBytes(NEWLINE);
				out.writeBytes(NEWLINE);
				// write content
				out.write(value);
				out.writeBytes(NEWLINE);
				out.flush();
				//
			} else {
				if(alreadyOuputParam) {
					out.writeBytes("&");
				} else {
					alreadyOuputParam = true;
				}
				out.writeBytes(name);
				out.writeBytes("=");
				out.write(value);
				out.flush();
			}
		}
	}
	private String readString() throws IOException {
		BufferedReader in = null;
		StringBuilder html = new StringBuilder();
		try {
			in = new BufferedReader(new InputStreamReader(con.getInputStream(), charSet));
			String line = null;
			while((line=in.readLine())!=null) {
				html.append(line);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if(in!=null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return html.toString();
	}
	private byte[] readByte() throws IOException {
		byte[] result = null;
		InputStream in = null;
		ByteArrayOutputStream bout = null;
		try {
			in = con.getInputStream();
			bout = new ByteArrayOutputStream();
			byte[] buff = new byte[1024*4];
			int len = -1;
			while((len=in.read(buff))!=-1) {
				bout.write(buff, 0, len);
			}
			result = bout.toByteArray();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if(in!=null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(bout!=null) {
				try {
					bout.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		return result;
	}
	/**
	 * 關閉連線並且讀取HTML。
	 * @return html，也許會null。
	 */
	public String closeAndReadString() {
		String html = null;
		try {
			if(isDoOuput) {
				if(isMultipart) {
					out.writeBytes(PREFIX);
					out.writeBytes(BOUNDARY);
					out.writeBytes(PREFIX);
					out.writeBytes(NEWLINE);
				}
				out.close();
			}
			html = readString();
		} catch (IOException e) {
			e.printStackTrace();
		}
		con.disconnect();
		return html;
	}
	/**
	 * 關閉連線並且讀取資料。
	 * @return byte datas，也許會null。
	 */
	public byte[] closeAndReadByteArray() {
		byte[] data = null;
		try {
			if(isDoOuput) {
				if(isMultipart) {
					out.writeBytes(PREFIX);
					out.writeBytes(BOUNDARY);
					out.writeBytes(PREFIX);
					out.writeBytes(NEWLINE);
				}
				out.close();
			}
			data = readByte();
		} catch (IOException e) {
			e.printStackTrace();
		}
		con.disconnect();
		return data;
	}
}